//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.docx4j;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Map.Entry;
import javax.xml.bind.Binder;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.UnmarshalException;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.util.JAXBResult;
import javax.xml.bind.util.JAXBSource;
import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.ErrorListener;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stax.StAXSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import org.apache.commons.io.IOUtils;
import org.docx4j.jaxb.Context;
import org.docx4j.jaxb.JAXBAssociation;
import org.docx4j.jaxb.JaxbValidationEventHandler;
import org.docx4j.jaxb.McIgnorableNamespaceDeclarator;
import org.docx4j.jaxb.NamespacePrefixMapperUtils;
import org.docx4j.jaxb.NamespacePrefixMappings;
import org.docx4j.jaxb.XPathBinderAssociationIsPartialException;
import org.docx4j.openpackaging.exceptions.Docx4JException;
import org.docx4j.org.apache.xalan.transformer.TransformerImpl;
import org.docx4j.org.apache.xml.security.Init;
import org.docx4j.org.apache.xml.security.c14n.CanonicalizationException;
import org.docx4j.org.apache.xml.security.c14n.Canonicalizer;
import org.docx4j.org.apache.xml.security.c14n.InvalidCanonicalizerException;
import org.docx4j.utils.XPathFactoryUtil;
import org.docx4j.utils.XmlSerializerUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
 * 重写 XmlUtils 工具类中unmarshallFromTemplate方法 以适配域变量
 */
public class XmlUtils {
    private static Logger log = LoggerFactory.getLogger(XmlUtils.class);
    public static String TRANSFORMER_FACTORY_PROCESSOR_XALAN = "org.docx4j.org.apache.xalan.processor.TransformerFactoryImpl";
    private static TransformerFactory transformerFactory;
    private static final DocumentBuilderFactory documentBuilderFactory;
    private static final String S_BUILTIN_EXTENSIONS_URL = "http://xml.apache.org/xalan";
    private static final String S_BUILTIN_EXTENSIONS_UNIVERSAL = "{http://xml.apache.org/xalan}";
    private static final String S_KEY_CONTENT_HANDLER = "{http://xml.apache.org/xalan}content-handler";

    public XmlUtils() {
    }

    public static TransformerFactory getTransformerFactory() {
        return transformerFactory;
    }

    /** @deprecated */
    @Deprecated
    public static DocumentBuilderFactory getDocumentBuilderFactory() {
        return documentBuilderFactory;
    }

    public static DocumentBuilder getNewDocumentBuilder() {
        synchronized(documentBuilderFactory) {
            DocumentBuilder var10000;
            try {
                var10000 = documentBuilderFactory.newDocumentBuilder();
            } catch (ParserConfigurationException var3) {
                log.error(var3.getMessage(), var3);
                return null;
            }

            return var10000;
        }
    }

    private static void instantiateTransformerFactory() {
        String originalSystemProperty = System.getProperty("javax.xml.transform.TransformerFactory");

        try {
            System.setProperty("javax.xml.transform.TransformerFactory", TRANSFORMER_FACTORY_PROCESSOR_XALAN);
            transformerFactory = TransformerFactory.newInstance();
            if (originalSystemProperty == null) {
                System.clearProperty("javax.xml.transform.TransformerFactory");
            } else {
                System.setProperty("javax.xml.transform.TransformerFactory", originalSystemProperty);
            }
        } catch (TransformerFactoryConfigurationError var2) {
            log.warn("Xalan jar missing from classpath; xslt not supported");
            if (originalSystemProperty == null) {
                System.clearProperty("javax.xml.transform.TransformerFactory");
            } else {
                System.setProperty("javax.xml.transform.TransformerFactory", originalSystemProperty);
            }

            transformerFactory = TransformerFactory.newInstance();
        }

        LoggingErrorListener errorListener = new LoggingErrorListener(false);
        transformerFactory.setErrorListener(errorListener);
    }

    public static Object unwrap(Object o) {
        if (o == null) {
            return null;
        } else if (o instanceof JAXBElement) {
            log.debug("Unwrapped " + ((JAXBElement)o).getDeclaredType().getName());
            log.debug("name: " + ((JAXBElement)o).getName());
            return ((JAXBElement)o).getValue();
        } else {
            return o;
        }
    }

    public static String JAXBElementDebug(JAXBElement o) {
        String prefix = null;
        if (o.getName().getNamespaceURI() != null) {
            try {
                prefix = NamespacePrefixMapperUtils.getPreferredPrefix(o.getName().getNamespaceURI(), (String)null, false);
            } catch (JAXBException var3) {
                var3.printStackTrace();
            }
        }

        return prefix != null ? prefix + ':' + o.getName().getLocalPart() + " is a javax.xml.bind.JAXBElement; it has declared type " + o.getDeclaredType().getName() : o.getName() + " is a javax.xml.bind.JAXBElement; it has declared type " + o.getDeclaredType().getName();
    }

    public static JAXBElement<?> getListItemByQName(List<JAXBElement<?>> list, QName name) {
        Iterator var2 = list.iterator();

        JAXBElement el;
        do {
            if (!var2.hasNext()) {
                return null;
            }

            el = (JAXBElement)var2.next();
        } while(!el.getName().equals(name));

        return el;
    }

    public static Object unmarshal(InputStream is) throws JAXBException {
        return unmarshal(is, Context.jc);
    }

    public static Object unmarshal(InputStream is, JAXBContext jc) throws JAXBException {
        XMLInputFactory xif = XMLInputFactory.newInstance();
        xif.setProperty("javax.xml.stream.isSupportingExternalEntities", false);
        xif.setProperty("javax.xml.stream.supportDTD", false);
        XMLStreamReader xsr = null;

        try {
            xsr = xif.createXMLStreamReader(is);
        } catch (XMLStreamException var11) {
            throw new JAXBException(var11);
        }

        Object o = null;
        Unmarshaller u = jc.createUnmarshaller();
        JaxbValidationEventHandler eventHandler = new JaxbValidationEventHandler();
        u.setEventHandler(eventHandler);

        try {
            o = u.unmarshal(xsr);
            return o;
        } catch (UnmarshalException var12) {
            if (var12.getLinkedException() != null && var12.getLinkedException().getMessage().contains("entity")) {
                log.error(var12.getMessage(), var12);
                throw var12;
            } else if (is.markSupported()) {
                log.info("encountered unexpected content; pre-processing");
                eventHandler.setContinue(true);

                try {
                    Templates mcPreprocessorXslt = JaxbValidationEventHandler.getMcPreprocessor();
                    is.reset();
                    JAXBResult result = prepareJAXBResult(jc);
                    xsr = xif.createXMLStreamReader(is);
                    transform((Source)(new StAXSource(xsr)), mcPreprocessorXslt, (Map)null, result);
                    return result.getResult();
                } catch (Exception var10) {
                    throw new JAXBException("Preprocessing exception", var10);
                }
            } else {
                log.error(var12.getMessage(), var12);
                log.error(".. and mark not supported");
                throw var12;
            }
        }
    }

    public static Object unmarshalString(String str) throws JAXBException {
        return unmarshalString(str, Context.jc);
    }

    public static Object unmarshalString(String str, JAXBContext jc, Class declaredType) throws JAXBException {
        Unmarshaller u = jc.createUnmarshaller();
        u.setEventHandler(new JaxbValidationEventHandler());

        Object o;
        try {
            DocumentBuilder db = getNewDocumentBuilder();
            InputStream is = IOUtils.toInputStream(str, "UTF-8");
            Throwable var7 = null;

            try {
                Document document = db.parse(is);
                o = u.unmarshal(document);
            } catch (Throwable var17) {
                var7 = var17;
                throw var17;
            } finally {
                if (is != null) {
                    if (var7 != null) {
                        try {
                            is.close();
                        } catch (Throwable var16) {
                            var7.addSuppressed(var16);
                        }
                    } else {
                        is.close();
                    }
                }

            }
        } catch (Exception var19) {
            throw new JAXBException(var19);
        }

        return o instanceof JAXBElement ? ((JAXBElement)o).getValue() : o;
    }

    public static Object unmarshalString(String str, JAXBContext jc) throws JAXBException {
        if (log.isDebugEnabled()) {
            log.debug("Unmarshalling '" + str + "'");
        }

        str = str.trim().replaceFirst("^([\\W]+)<", "<");
        Unmarshaller u = jc.createUnmarshaller();
        JaxbValidationEventHandler eventHandler = new JaxbValidationEventHandler();
        u.setEventHandler(eventHandler);
        Document document = null;

        try {
            DocumentBuilder db = getNewDocumentBuilder();
            InputStream is = IOUtils.toInputStream(str, "UTF-8");
            Throwable var27 = null;

            try {
                document = db.parse(is);
            } catch (Throwable var21) {
                var27 = var21;
                throw var21;
            } finally {
                if (is != null) {
                    if (var27 != null) {
                        try {
                            is.close();
                        } catch (Throwable var20) {
                            var27.addSuppressed(var20);
                        }
                    } else {
                        is.close();
                    }
                }

            }

            return u.unmarshal(document);
        } catch (IOException var23) {
            throw new UnmarshalException(var23);
        } catch (UnmarshalException var24) {
            if (var24.getLinkedException() != null && var24.getLinkedException().getMessage().contains("entity")) {
                if (var24.getMessage() == null) {
                    log.error("entity parse exception", var24);
                } else {
                    log.error(var24.getMessage(), var24);
                }

                throw var24;
            } else {
                log.info("encountered unexpected content; pre-processing");
                eventHandler.setContinue(true);

                try {
                    Templates mcPreprocessorXslt = JaxbValidationEventHandler.getMcPreprocessor();
                    JAXBResult result = prepareJAXBResult(jc);
                    transform((Document)document, mcPreprocessorXslt, (Map)null, result);
                    return result.getResult();
                } catch (Exception var19) {
                    throw new JAXBException("Preprocessing exception", var19);
                }
            }
        } catch (SAXException var25) {
            throw new UnmarshalException(var25);
        }
    }

    public static Object unmarshal(Node n) throws JAXBException {
        Unmarshaller u = Context.jc.createUnmarshaller();
        JaxbValidationEventHandler veh = new JaxbValidationEventHandler();
        veh.setContinue(true);
        u.setEventHandler(veh);
        return u.unmarshal(n);
    }

    public static Object unmarshal(Node n, JAXBContext jc, Class declaredType) throws JAXBException {
        Unmarshaller u = jc.createUnmarshaller();
        u.setEventHandler(new JaxbValidationEventHandler());
        Object o = u.unmarshal(n, declaredType);
        return o instanceof JAXBElement ? ((JAXBElement)o).getValue() : o;
    }

    public static Object unmarshallFromTemplate(String wmlTemplateString, Map<String, ?> mappings) throws JAXBException {
        return unmarshallFromTemplate(wmlTemplateString, mappings, Context.jc);
    }

    public static Object unmarshallFromTemplate(String wmlTemplateString, Map<String, ?> mappings, JAXBContext jc) throws JAXBException {
        /**
         * 重写 XmlUtils 工具类中unmarshallFromTemplate方法 以适配域变量 gaoxueyong 2 minutes ago
         */
        wmlTemplateString=wmlTemplateString.replace("«$","$").replace("}»","}");
        String wmlString = replace(wmlTemplateString, new StringBuilder(), mappings).toString();
        log.debug("Results of substitution: " + wmlString);
        return unmarshalString(wmlString, jc);
    }

    public static Object unmarshallFromTemplate(String wmlTemplateString, Map<String, ?> mappings, JAXBContext jc, Class<?> declaredType) throws JAXBException {
        String wmlString = replace(wmlTemplateString, new StringBuilder(), mappings).toString();
        return unmarshalString(wmlString, jc, declaredType);
    }

    private static StringBuilder replace(String wmlTemplateString, StringBuilder strB, Map<String, ?> mappings) {
        int offset = 0;

        while(true) {
//        }»
            int startKey = wmlTemplateString.indexOf("${", offset);
//            int startKey = wmlTemplateString.indexOf("«${", offset);
            if (startKey == -1) {
                return strB.append(wmlTemplateString.substring(offset));
            }

            strB.append(wmlTemplateString.substring(offset, startKey));
            int keyEnd = wmlTemplateString.indexOf(125, startKey);
//            int keyEnd = wmlTemplateString.indexOf(" }»", startKey);
            String key = wmlTemplateString.substring(startKey + 2, keyEnd);
            Object val = mappings.get(key);
            if (val == null) {
                log.warn("Invalid key '" + key + "' or key not mapped to a value");
                strB.append(key);
            } else {
                strB.append(val.toString());
            }

            offset = keyEnd + 1;
        }
    }

    public static String marshaltoString(Object o) {
        JAXBContext jc = Context.jc;
        return marshaltoString(o, true, true, jc);
    }

    public static String marshaltoString(Object o, JAXBContext jc) {
        return marshaltoString(o, true, true, jc);
    }

    /** @deprecated */
    @Deprecated
    public static String marshaltoString(Object o, boolean suppressDeclaration) {
        JAXBContext jc = Context.jc;
        return marshaltoString(o, suppressDeclaration, false, jc);
    }

    /** @deprecated */
    @Deprecated
    public static String marshaltoString(Object o, boolean suppressDeclaration, JAXBContext jc) {
        return marshaltoString(o, suppressDeclaration, false, jc);
    }

    public static String marshaltoString(Object o, boolean suppressDeclaration, boolean prettyprint) {
        JAXBContext jc = Context.jc;
        return marshaltoString(o, suppressDeclaration, prettyprint, jc);
    }

    private static String setMcIgnorable(McIgnorableNamespaceDeclarator prefixMapper, Object o) {
        if (o instanceof org.docx4j.wml.Document) {
            String ignorables = ((org.docx4j.wml.Document)o).getIgnorable();
            if (ignorables != null) {
                prefixMapper.setMcIgnorable(ignorables);
            }

            return ignorables;
        } else {
            return null;
        }
    }

    public static byte[] trimNamespaces(Document doc, String ignorables) throws InvalidCanonicalizerException, CanonicalizationException {
        log.debug("Input to Canonicalizer: " + w3CDomNodeToString(doc));
        Init.init();
        Canonicalizer c = Canonicalizer.getInstance("http://www.w3.org/2001/10/xml-exc-c14n#");
        return c.canonicalizeSubtree(doc, ignorables);
    }

    public static String marshaltoString(Object o, boolean suppressDeclaration, boolean prettyprint, JAXBContext jc) {
        if (o == null) {
            return null;
        } else {
            try {
                Marshaller m = jc.createMarshaller();
                NamespacePrefixMapperUtils.setProperty(m, NamespacePrefixMapperUtils.getPrefixMapper());
                String ignorables = setMcIgnorable((McIgnorableNamespaceDeclarator)NamespacePrefixMapperUtils.getPrefixMapper(), o);
                if (prettyprint) {
                    m.setProperty("jaxb.formatted.output", true);
                }

                if (suppressDeclaration) {
                    m.setProperty("jaxb.fragment", true);
                }

                if (Docx4jProperties.getProperty("docx4j.jaxb.marshal.canonicalize", false)) {
                    Document doc = marshaltoW3CDomDocument(o, jc);
                    byte[] bytes = trimNamespaces(doc, ignorables);
                    return new String(bytes, "UTF-8");
                } else {
                    StringWriter sWriter = new StringWriter();
                    m.marshal(o, sWriter);
                    return sWriter.toString();
                }
            } catch (Exception var8) {
                throw new RuntimeException(var8);
            }
        }
    }

    public static String marshaltoString(Object o, boolean suppressDeclaration, boolean prettyprint, JAXBContext jc, String uri, String local, Class declaredType) {
        try {
            Marshaller m = jc.createMarshaller();
            NamespacePrefixMapperUtils.setProperty(m, NamespacePrefixMapperUtils.getPrefixMapper());
            String ignorables = setMcIgnorable((McIgnorableNamespaceDeclarator)NamespacePrefixMapperUtils.getPrefixMapper(), o);
            if (prettyprint) {
                m.setProperty("jaxb.formatted.output", true);
            }

            if (suppressDeclaration) {
                m.setProperty("jaxb.fragment", true);
            }

            if (Docx4jProperties.getProperty("docx4j.jaxb.marshal.canonicalize", false)) {
                Document doc = marshaltoW3CDomDocument(o, jc, uri, local, declaredType);
                byte[] bytes = trimNamespaces(doc, ignorables);
                return new String(bytes, "UTF-8");
            } else {
                StringWriter sWriter = new StringWriter();
                m.marshal(new JAXBElement(new QName(uri, local), declaredType, o), sWriter);
                return sWriter.toString();
            }
        } catch (Exception var11) {
            throw new RuntimeException(var11);
        }
    }

    public static InputStream marshaltoInputStream(Object o, boolean suppressDeclaration, JAXBContext jc) {
        try {
            Marshaller m = jc.createMarshaller();
            NamespacePrefixMapperUtils.setProperty(m, NamespacePrefixMapperUtils.getPrefixMapper());
            String ignorables = setMcIgnorable((McIgnorableNamespaceDeclarator)NamespacePrefixMapperUtils.getPrefixMapper(), o);
            if (suppressDeclaration) {
                m.setProperty("jaxb.fragment", true);
            }

            ByteArrayOutputStream os = new ByteArrayOutputStream();
            m.marshal(o, os);
            if (Docx4jProperties.getProperty("docx4j.jaxb.marshal.canonicalize", false)) {
                Document doc = marshaltoW3CDomDocument(o, jc);
                byte[] bytes = trimNamespaces(doc, ignorables);
                return new ByteArrayInputStream(bytes);
            } else {
                return new ByteArrayInputStream(os.toByteArray());
            }
        } catch (Exception var8) {
            throw new RuntimeException(var8);
        }
    }

    public static Document marshaltoW3CDomDocument(Object o) {
        return marshaltoW3CDomDocument(o, Context.jc);
    }

    public static Document marshaltoW3CDomDocument(Object o, JAXBContext jc) {
        try {
            Marshaller marshaller = jc.createMarshaller();
            NamespacePrefixMapperUtils.setProperty(marshaller, NamespacePrefixMapperUtils.getPrefixMapper());
            String ignorables = setMcIgnorable((McIgnorableNamespaceDeclarator)NamespacePrefixMapperUtils.getPrefixMapper(), o);
            Document doc = getNewDocumentBuilder().newDocument();
            marshaller.marshal(o, doc);
            if (Docx4jProperties.getProperty("docx4j.jaxb.marshal.canonicalize", false)) {
                byte[] bytes = trimNamespaces(doc, ignorables);
                DocumentBuilder builder = getDocumentBuilderFactory().newDocumentBuilder();
                return builder.parse(new ByteArrayInputStream(bytes));
            } else {
                return doc;
            }
        } catch (Exception var7) {
            throw new RuntimeException(var7);
        }
    }

    public static Document marshaltoW3CDomDocument(Object o, JAXBContext jc, String uri, String local, Class declaredType) {
        try {
            Marshaller marshaller = jc.createMarshaller();
            NamespacePrefixMapperUtils.setProperty(marshaller, NamespacePrefixMapperUtils.getPrefixMapper());
            String ignorables = setMcIgnorable((McIgnorableNamespaceDeclarator)NamespacePrefixMapperUtils.getPrefixMapper(), o);
            Document doc = getNewDocumentBuilder().newDocument();
            marshaller.marshal(new JAXBElement(new QName(uri, local), declaredType, o), doc);
            if (Docx4jProperties.getProperty("docx4j.jaxb.marshal.canonicalize", false)) {
                byte[] bytes = trimNamespaces(doc, ignorables);
                DocumentBuilder builder = getDocumentBuilderFactory().newDocumentBuilder();
                return builder.parse(new ByteArrayInputStream(bytes));
            } else {
                return doc;
            }
        } catch (Exception var10) {
            throw new RuntimeException(var10);
        }
    }

    public static <T> T deepCopy(T value) {
        return deepCopy(value, Context.jc);
    }

    public static <T> T deepCopy(T value, JAXBContext jc) {
        if (value == null) {
            throw new IllegalArgumentException("Can't clone a null argument");
        } else {
            try {
                JAXBElement elem;
                Object res;
                if (value instanceof JAXBElement) {
                    res = ((JAXBElement)value).getValue();
                    QName qname = ((JAXBElement)value).getName();
                    Class clazz = res.getClass();
                    JAXBElement contentObject = new JAXBElement(qname, clazz, res);
                    JAXBSource source = new JAXBSource(jc, contentObject);
                    elem = jc.createUnmarshaller().unmarshal(source, clazz);
                } else {
                    Class<T> clazz = (Class<T>) value.getClass();
                    JAXBElement<T> contentObject = new JAXBElement(new QName(clazz.getSimpleName()), clazz, value);
                    JAXBSource source = new JAXBSource(jc, contentObject);
                    elem = jc.createUnmarshaller().unmarshal(source, clazz);
                }

                if (value instanceof JAXBElement) {
                    res = elem;
                } else {
                    T resT = (T) elem.getValue();
                    res = resT;
                }

                return (T) res;
            } catch (JAXBException var8) {
                throw new IllegalArgumentException(var8);
            }
        }
    }

    public static String w3CDomNodeToString(Node n) {
        StringWriter sw = new StringWriter();

        try {
            XmlSerializerUtil.serialize(new DOMSource(n), new StreamResult(sw), true, true);
            return sw.toString();
        } catch (Exception var3) {
            log.error(var3.getMessage(), var3);
            return null;
        }
    }

    public static void w3CDomNodeToOutputStream(Node n, OutputStream os) throws Docx4JException {
        XmlSerializerUtil.serialize(new DOMSource(n), new StreamResult(os), true, true);
    }

    public static Document neww3cDomDocument() {
        return getNewDocumentBuilder().newDocument();
    }

    public static void appendXmlFragment(Document document, Node parent, String fragment) throws IOException, SAXException, ParserConfigurationException {
        Node fragmentNode = getNewDocumentBuilder().parse(new InputSource(new StringReader(fragment))).getDocumentElement();
        fragmentNode = document.importNode(fragmentNode, true);
        parent.appendChild(fragmentNode);
    }

    public static JAXBResult prepareJAXBResult(JAXBContext context) throws Docx4JException {
        try {
            Unmarshaller unmarshaller = context.createUnmarshaller();
            unmarshaller.setEventHandler(new JaxbValidationEventHandler());
            JAXBResult result = new JAXBResult(unmarshaller);
            return result;
        } catch (JAXBException var3) {
            throw new Docx4JException("Error preparing empty JAXB result", var3);
        }
    }

    public static void transform(Document doc, Templates template, Map<String, Object> transformParameters, Result result) throws Docx4JException {
        if (doc == null) {
            Throwable t = new Throwable();
            throw new Docx4JException("Null DOM Doc", t);
        } else {
            DOMSource domSource = new DOMSource(doc);
            transform((Source)domSource, template, transformParameters, result);
        }
    }

    public static Templates getTransformerTemplate(Source xsltSource) throws TransformerConfigurationException {
        return transformerFactory.newTemplates(xsltSource);
    }

    public static void transform(Source source, Templates template, Map<String, Object> transformParameters, Result result) throws Docx4JException {
        if (source == null) {
            Throwable t = new Throwable();
            throw new Docx4JException("Null Source doc", t);
        } else {
            Transformer xformer;
            try {
                xformer = template.newTransformer();
            } catch (TransformerConfigurationException var14) {
                throw new Docx4JException("The Transformer is ill-configured", var14);
            }

            log.info("Using " + xformer.getClass().getName());
            if (xformer.getClass().getName().equals("org.docx4j.org.apache.xalan.transformer.TransformerImpl")) {
                Properties p = xformer.getOutputProperties();
                String method = p.getProperty("method");
                if (method != null && !method.equals("xml")) {
                    if (method.equals("html")) {
                        ((TransformerImpl)xformer).setOutputProperty("{http://xml.apache.org/xalan}content-handler", "org.docx4j.org.apache.xml.serializer.ToHTMLStream");
                    } else if (method.equals("text")) {
                        ((TransformerImpl)xformer).setOutputProperty("{http://xml.apache.org/xalan}content-handler", "org.docx4j.org.apache.xml.serializer.ToTextStream");
                    } else {
                        log.warn("fallback for method: " + method);
                        ((TransformerImpl)xformer).setOutputProperty("{http://xml.apache.org/xalan}content-handler", "org.docx4j.org.apache.xml.serializer.ToUnknownStream");
                    }
                } else {
                    ((TransformerImpl)xformer).setOutputProperty("{http://xml.apache.org/xalan}content-handler", "org.docx4j.org.apache.xml.serializer.ToXMLStream");
                }
            } else {
                log.error("Detected " + xformer.getClass().getName() + ", but require org.docx4j.org.apache.xalan.transformer.TransformerImpl. ");
            }

            LoggingErrorListener errorListener = new LoggingErrorListener(false);
            xformer.setErrorListener(errorListener);
            if (transformParameters != null) {
                Iterator parameterIterator = transformParameters.entrySet().iterator();

                while(parameterIterator.hasNext()) {
                    Entry pairs = (Entry)parameterIterator.next();
                    if (pairs.getKey() == null) {
                        log.info("Skipped null key");
                    } else if (!pairs.getKey().equals("customXsltTemplates")) {
                        if (pairs.getValue() == null) {
                            log.warn("parameter '" + pairs.getKey() + "' was null.");
                        } else {
                            xformer.setParameter((String)pairs.getKey(), pairs.getValue());
                        }
                    }
                }
            }

            try {
                xformer.transform(source, result);
            } catch (TransformerException var12) {
                throw new Docx4JException("Cannot perform the transformation", var12);
            } finally {
                ;
            }
        }
    }

    public static List<Object> getJAXBNodesViaXPath(Binder<Node> binder, Object jaxbElement, String xpathExpr, boolean refreshXmlFirst) throws JAXBException, XPathBinderAssociationIsPartialException {
        List<JAXBAssociation> associations = getJAXBAssociationsForXPath(binder, jaxbElement, xpathExpr, refreshXmlFirst);
        List<Object> resultList = new ArrayList();
        Iterator var6 = associations.iterator();

        while(var6.hasNext()) {
            JAXBAssociation association = (JAXBAssociation)var6.next();
            if (association.getJaxbObject() == null) {
                throw new XPathBinderAssociationIsPartialException("no object association for xpath result: " + association.getDomNode().getNodeName());
            }

            resultList.add(association.getJaxbObject());
        }

        return resultList;
    }

    public static List<JAXBAssociation> getJAXBAssociationsForXPath(Binder<Node> binder, Object jaxbElement, String xpathExpr, boolean refreshXmlFirst) throws JAXBException, XPathBinderAssociationIsPartialException {
        if (binder == null) {
            log.warn("null binder");
        }

        if (jaxbElement == null) {
            log.warn("null jaxbElement");
        }

        Node node;
        if (refreshXmlFirst) {
            node = (Node)binder.updateXML(jaxbElement);
        }

        node = (Node)binder.getXMLNode(jaxbElement);
        if (node == null) {
            throw new XPathBinderAssociationIsPartialException("binder.getXMLNode returned null");
        } else {
            List<JAXBAssociation> resultList = new ArrayList();
            Iterator var6 = xpath(node, xpathExpr).iterator();

            while(var6.hasNext()) {
                Node n = (Node)var6.next();
                resultList.add(new JAXBAssociation(n, binder.getJAXBNode(n)));
            }

            return resultList;
        }
    }

    public static List<Node> xpath(Node node, String xpathExpression) {
        NamespaceContext nsContext = new NamespacePrefixMappings();
        return xpath(node, xpathExpression, nsContext);
    }

    public static List<Node> xpath(Node node, String xpathExpression, NamespaceContext nsContext) {
        if (log.isDebugEnabled()) {
            log.debug(w3CDomNodeToString(node));
        }

        XPath xpath = XPathFactoryUtil.newXPath();

        try {
            List<Node> result = new ArrayList();
            xpath.setNamespaceContext(nsContext);
            NodeList nl = (NodeList)xpath.evaluate(xpathExpression, node, XPathConstants.NODESET);
            if (log.isDebugEnabled()) {
                log.debug("evaluate returned " + nl.getLength());
            }

            if (nl.getLength() == 0) {
                log.info("no results for xpath " + xpathExpression);
            }

            for(int i = 0; i < nl.getLength(); ++i) {
                result.add(nl.item(i));
            }

            return result;
        } catch (XPathExpressionException var7) {
            throw new RuntimeException("Problem with '" + xpathExpression + "'", var7);
        }
    }

    public static void treeCopy(NodeList sourceNodes, Node destParent) {
        for(int i = 0; i < sourceNodes.getLength(); ++i) {
            treeCopy(sourceNodes.item(i), destParent);
        }

    }

    public static void treeCopy(Node sourceNode, Node destParent) {
        log.debug("node type" + sourceNode.getNodeType());
        switch(sourceNode.getNodeType()) {
            case 1:
                log.debug("copying: " + sourceNode.getNodeName());
                Element newChild;
                if (destParent instanceof Document) {
                    newChild = ((Document)destParent).createElementNS(sourceNode.getNamespaceURI(), sourceNode.getLocalName());
                } else if (sourceNode.getNamespaceURI() != null) {
                    newChild = destParent.getOwnerDocument().createElementNS(sourceNode.getNamespaceURI(), sourceNode.getLocalName());
                } else {
                    newChild = destParent.getOwnerDocument().createElement(sourceNode.getNodeName());
                }

                destParent.appendChild(newChild);
                NamedNodeMap atts = sourceNode.getAttributes();

                for(int i = 0; i < atts.getLength(); ++i) {
                    Attr attr = (Attr)atts.item(i);
                    if (!attr.getNodeName().startsWith("xmlns:")) {
                        if (attr.getNamespaceURI() == null) {
                            ((Element)newChild).setAttribute(attr.getName(), attr.getValue());
                        } else if (!attr.getNamespaceURI().equals("http://www.w3.org/2000/xmlns/")) {
                            if (attr.getNodeName() != null) {
                                ((Element)newChild).setAttributeNS(attr.getNamespaceURI(), attr.getNodeName(), attr.getValue());
                            } else {
                                ((Element)newChild).setAttributeNS(attr.getNamespaceURI(), attr.getLocalName(), attr.getValue());
                            }
                        }
                    }
                }

                NodeList children = sourceNode.getChildNodes();
                if (children != null) {
                    for(int i = 0; i < children.getLength(); ++i) {
                        treeCopy((Node)children.item(i), newChild);
                    }
                }
                break;
            case 3:
                Text textNode;
                if (destParent.getOwnerDocument() == null && destParent.getNodeName().equals("#document")) {
                    textNode = ((Document)destParent).createTextNode(sourceNode.getNodeValue());
                    destParent.appendChild(textNode);
                } else {
                    textNode = destParent.getOwnerDocument().createTextNode(sourceNode.getNodeValue());
                    destParent.appendChild(textNode);
                }
                break;
            case 9:
            case 11:
                NodeList nodes = sourceNode.getChildNodes();
                if (nodes != null) {
                    for(int i = 0; i < nodes.getLength(); ++i) {
                        log.debug("child " + i + "of DOCUMENT_NODE");
                        treeCopy(nodes.item(i), destParent);
                    }
                }
        }

    }

    static {
        instantiateTransformerFactory();
        log.debug(System.getProperty("java.vendor"));
        log.debug(System.getProperty("java.version"));
        String sp = Docx4jProperties.getProperty("javax.xml.parsers.SAXParserFactory");
        if (sp != null) {
            System.setProperty("javax.xml.parsers.SAXParserFactory", sp);
            log.info("setProperty " + sp + " (from docx4j.properties)");
        } else if (Docx4jProperties.getProperty("docx4j.javax.xml.parsers.SAXParserFactory.donotset", false)) {
            log.info("Not setting docx4j.javax.xml.parsers.SAXParserFactory");
        } else if ((!System.getProperty("java.version").startsWith("1.6") || !System.getProperty("java.vendor").startsWith("Sun")) && !System.getProperty("java.vendor").startsWith("Oracle") && (!System.getProperty("java.version").startsWith("1.7") || !System.getProperty("java.vendor").startsWith("Jeroen"))) {
            if ("org.apache.xerces.jaxp.SAXParserFactoryImpl".equals(System.getProperty("javax.xml.parsers.SAXParserFactory"))) {
                log.info("xerces SAXParserFactory in use");
            } else {
                log.warn("default SAXParserFactory property : " + System.getProperty("javax.xml.parsers.SAXParserFactory") + "\n Please consider using Xerces.");
            }
        } else {
            System.setProperty("javax.xml.parsers.SAXParserFactory", "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl");
            log.info("setProperty com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl");
        }

        log.info("actual: " + SAXParserFactory.newInstance().getClass().getName());
        String dbf = Docx4jProperties.getProperty("javax.xml.parsers.DocumentBuilderFactory");
        if (dbf != null) {
            System.setProperty("javax.xml.parsers.DocumentBuilderFactory", dbf);
            log.info("setProperty " + dbf + " (from docx4j.properties)");
        } else if (Docx4jProperties.getProperty("docx4j.javax.xml.parsers.DocumentBuilderFactory.donotset", false)) {
            log.info("Not setting docx4j.javax.xml.parsers.DocumentBuilderFactory");
        } else if ((!System.getProperty("java.version").startsWith("1.6") || !System.getProperty("java.vendor").startsWith("Sun")) && !System.getProperty("java.vendor").startsWith("Oracle") && (!System.getProperty("java.version").startsWith("1.7") || !System.getProperty("java.vendor").startsWith("Jeroen"))) {
            if ("org.apache.xerces.jaxp.DocumentBuilderFactoryImpl".equals(System.getProperty("javax.xml.parsers.DocumentBuilderFactory"))) {
                log.info("xerces DocumentBuilderFactory in use");
            } else {
                log.warn("default DocumentBuilderFactory property: " + System.getProperty("javax.xml.parsers.DocumentBuilderFactory") + "\n Please consider using Xerces.");
            }
        } else {
            System.setProperty("javax.xml.parsers.DocumentBuilderFactory", "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl");
            log.info("setProperty com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl");
        }

        documentBuilderFactory = DocumentBuilderFactory.newInstance();
        log.info("actual: " + documentBuilderFactory.getClass().getName());
        documentBuilderFactory.setNamespaceAware(true);

        StackTraceElement[] elements;
        try {
            documentBuilderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
        } catch (ParserConfigurationException var8) {
            log.warn(var8.getMessage());
            elements = var8.getStackTrace();
            if (elements.length > 0) {
                log.warn(elements[0].toString());
            }
        }

        try {
            documentBuilderFactory.setXIncludeAware(false);
        } catch (Exception var7) {
            log.warn(var7.getMessage());
            elements = var7.getStackTrace();
            if (elements.length > 0) {
                log.warn(elements[0].toString());
            }
        }

        try {
            documentBuilderFactory.setExpandEntityReferences(false);
        } catch (Exception var6) {
            log.warn(var6.getMessage());
            elements = var6.getStackTrace();
            if (elements.length > 0) {
                log.warn(elements[0].toString());
            }
        }

        try {
            documentBuilderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
        } catch (ParserConfigurationException var5) {
            log.warn(var5.getMessage());
            elements = var5.getStackTrace();
            if (elements.length > 0) {
                log.warn(elements[0].toString());
            }
        }

        try {
            documentBuilderFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);
        } catch (ParserConfigurationException var4) {
            log.warn(var4.getMessage());
            elements = var4.getStackTrace();
            if (elements.length > 0) {
                log.warn(elements[0].toString());
            }
        }

    }

    static class LoggingErrorListener implements ErrorListener {
        boolean strict;

        public LoggingErrorListener(boolean strict) {
        }

        @Override
        public void warning(TransformerException exception) {
            XmlUtils.log.warn(exception.getMessage(), exception);
        }

        @Override
        public void error(TransformerException exception) throws TransformerException {
            XmlUtils.log.error(exception.getMessage(), exception);
            if (this.strict) {
                throw exception;
            }
        }

        @Override
        public void fatalError(TransformerException exception) throws TransformerException {
            if (Docx4jProperties.getProperty("docx4j.openpackaging.exceptions.LogBeforeThrow", true)) {
                XmlUtils.log.error(exception.getMessage(), exception);
            }

            throw exception;
        }
    }
}